package com.horizon.cloud.standard.lock;

import cn.hutool.core.thread.ThreadUtil;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

@Slf4j
@Data
@AllArgsConstructor
public class JedisLock  implements Lock {
    //拿到锁的线程
    private Thread thread;

    //拿到锁的状态
    private volatile int state = 0;

    public static final int DEFAULT_TIMEOUT = 2000;
    public static final Long WAIT_GAT = Long.valueOf(100);

    InnerLock innerLock = null;
    /**
     * 默认为2000ms
     */
    long expire = 2000L;

    public JedisLock(String lockKey, String requestId) {
        innerLock = new InnerLock(lockKey, requestId);

    }
    @Override
    public void lock() {
        if(innerLock== null) {
            return;
        }
        this.innerLock.lock();
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {

    }

    //模仿ReentrantLock的tryAcqui
    @Override
    public boolean tryLock() {
return state !=0 ?true:false;
    }

    /**
     * 超时返回失败
     * @param time
     * @param unit
     * @return
     * @throws InterruptedException
     */
    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        //本地可重入
        if(state!= 0 && thread == Thread.currentThread()) {
            return true;
        }
        expire = unit != null ?unit.toMillis(time):DEFAULT_TIMEOUT;
        long startMills = System.currentTimeMillis();
        Long millisToWait = expire;

        boolean localLocked = false;

        int turn = 1;
        while(!localLocked) {
            localLocked = this.innerLock.lock(expire);
            //如果没有加锁成功,看下加锁过期时间是否已经超了
            if (!localLocked) {
                millisToWait = millisToWait -
                        (System.currentTimeMillis()- startMills);
                startMills = System.currentTimeMillis();
                if (millisToWait>0) {
                    //没有超时，停留一会继续枷锁
                    ThreadUtil.sleep(WAIT_GAT, TimeUnit.MILLISECONDS);

                } else {
                    return false;
                }
            } else {
                state +=1;
                localLocked = true;
                thread = Thread.currentThread();
            }
        }
        return state ==0 ?false:true;
    }

    @Override
    public void unlock() {
        if (innerLock == null) {
            return;
        }
        this.innerLock.unlock();
        state=0;
        thread = null;
    }

    @Override
    public Condition newCondition() {
        return null;
    }
}
